import { ServerConnectAction } from '@/server/action'
import { START_UPDATE, UPDATE_SUCCESS, UPDATE_FAILURE } from '@/enums/identifier'
import type { ActionsNext } from '@/utils/action'
import type { ServerConnect } from '@/server/connect'
import type { FileStructureDiffResult } from '@/utils/fileStructure'
import { sleep } from '@/utils/common'

export class UpdateFileAction extends ServerConnectAction {
  constructor(connect: ServerConnect) {
    super('updateFile', connect)

    this.addAsyncAction('startUpdate', this.startUpdate_handler, true)
    this.addAction('updateFile', this.updateFile_handler)
    this.addAsyncAction('updateSuccess', this.updateSuccess_handler)
    this.addAsyncAction('updateFailure', this.updateFailure_handler)

    this.actions.addBranchList([
      ['startUpdate', 'updateFile'],
      ['updateFile', 'updateSuccess'],
      ['updateFile', 'updateFailure']
    ])
  }

  readonly minUpdateTime = 200

  async startUpdate_handler() {
    await this.connect.waitDrain(3000, 500)
    await this.connect.sendText(START_UPDATE)
  }

  async updateFile_handler(next: ActionsNext) {
    const project = this.connect.project
    if (!project) return this.fail('project not init')

    const fileStructureDiffResult =
      this.connect.store.get<FileStructureDiffResult>('fileStructureDiffResult')
    if (!fileStructureDiffResult) return this.fail('fileStructureDiffResult not exist')

    this.connect.startIntervalSendPong(1000, false)
    const startTime = Date.now()
    this.logger.info('start update file')
    project
      .updateFile(fileStructureDiffResult)
      .then(async () => {
        const time = Date.now() - startTime
        if (time < this.minUpdateTime) await sleep(this.minUpdateTime - time)
        next('updateSuccess')
      })
      .catch((err) => {
        this.logger.error(err)
        next('updateFailure')
      })
      .finally(() => {
        this.connect.stopIntervalSendPong()
      })
  }

  async updateSuccess_handler() {
    this.logger.info('update file success')
    await this.connect.sendText(UPDATE_SUCCESS)
  }

  async updateFailure_handler() {
    this.logger.info('update file failure')
    await this.connect.sendText(UPDATE_FAILURE)
  }
}
